﻿/* 
 * Copyright 2010 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;
using Ngilead.Core.Exception;
using log4net;

namespace Ngilead.Core.Replicator
{
    /// <summary>
    /// Replicator for arrays (IList)
    /// </summary>
    public class ArrayReplicator : AbstractReplicator
    {
        #region Attributes

        /// <summary> Logger channel</summary>
        private static ILog logger = LogManager.GetLogger(typeof(CollectionReplicator));

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public ArrayReplicator()
        { }

        #endregion

        #region Public interface

        /// <summary>
        /// Replicate the argument array, using the toClass for different class handling.
        /// </summary>
        public virtual T ReplicateArray<T>(T fromArray) where T : IList
        {
            if (logger.IsInfoEnabled)
            {
                logger.Info(String.Format("ReplicateArray<T>(fromArray) : where T is {0}", typeof(T).ToString()));
            }

            T toArray;
            try
            {
                toArray = CreateToArray(fromArray);

                // put TargetCloned
                PutTargetCloned(fromArray, toArray);

                // recursively populate member objects.
                Int32 index = 0;
                foreach (Object fromMember in fromArray)
                {
                    if (fromMember == null)
                    {
                        Type GType = fromArray.GetType().GetElementType();
                        toArray[index] = (GType.IsValueType) ? Activator.CreateInstance(GType) : null;
                    }
                    else
                    {
                        toArray[index] = BeanTransformer.Replicate(fromMember);
                    }
                    index++;
                }
            }
            catch (System.Exception ex)
            {
                throw new CloneException(ex.Message, ex);
            }

            return toArray;
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Create a new (empty) collection of the same type as the argument
        /// </summary>
        /// <typeparam name="T">IList</typeparam>
        /// <param name="from">The input collection</param>
        /// <returns>The new empty collection</returns>
        protected virtual T CreateToArray<T>(T from) where T : IList
        {
            return CollectionUtil.CreateToArray(from);
        }

        #endregion
    }
}
